#include <assert.h>
#include <stdlib.h>
#include <stdio.h>

#include "OBLBasic_Table.h"
#include "sthread.h"


void OBLT_init(OBLBasicTable *t, int nPlates)
{
  t->chopsticks.sticks  = malloc(nPlates * sizeof(int));            // dynamically allocate an array of size nPlates
  t->chopsticks.length  = nPlates;
  smutex_init(&(t->mutex));                                         // initialize the mutex
  scond_init(&(t->cond), &(t->mutex));                              // initialize the condition variable, link it to the mutex
}


void OBLT_startEating(OBLBasicTable *t, int philosopher)
{
  assert(NULL != t->mutex);
  // grab the lock
  smutex_lock(&(t->mutex));

  // check to see if adjacent chopsticks are taken
  // coding standards say to use a while
  // the long index implements wrap around
  while(1 == t->chopsticks.sticks[philosopher] || 1 == t->chopsticks.sticks[(philosopher-1)>=0?(philosopher-1):(t->chopsticks.length-1)])
  {// if yes...
    scond_wait(&(t->cond),&(t->mutex)); // wait
  }

  assert(1 != t->chopsticks.sticks[philosopher]);
  assert(1 != t->chopsticks.sticks[(philosopher-1)>=0?(philosopher-1):(t->chopsticks.length-1)]);
  t->chopsticks.sticks[philosopher]                                                 = 1; // claim the chopsticks
  t->chopsticks.sticks[(philosopher-1)>=0?(philosopher-1):(t->chopsticks.length-1)] = 1;

  assert(t->chopsticks.sticks[philosopher] == 1);
  assert(t->chopsticks.sticks[(philosopher-1)>=0?(philosopher-1):(t->chopsticks.length-1)] == 1);

  // signal for the next philosopher
  scond_signal(&(t->cond),&(t->mutex));

  // return the lock
  smutex_unlock(&(t->mutex));
}

void OBLT_doneEating(OBLBasicTable *t, int philosopher)
{
  // grab the lock
  smutex_lock(&(t->mutex));

  t->chopsticks.sticks[philosopher]                                                 = 0; // release the chopsticks
  t->chopsticks.sticks[(philosopher-1)>=0?(philosopher-1):(t->chopsticks.length-1)] = 0;

  assert(t->chopsticks.sticks[philosopher] == 0);
  assert(t->chopsticks.sticks[(philosopher-1)>=0?(philosopher-1):(t->chopsticks.length-1)] == 0)

  // signal for the next philosopher
  scond_signal(&(t->cond),&(t->mutex));

  // return the lock
  smutex_unlock(&(t->mutex));
}
